import 'package:lunar/lunar.dart';

/// 农历服务类 - Lunar service class
/// 使用lunar库提供老黄历相关功能 - Uses lunar library to provide lunar calendar functions
/// 包括农历日期转换、宜忌查询、节气计算等 - Including lunar date conversion, suitable/unsuitable activities query, solar terms calculation, etc.
/// 
/// 基于6tail lunar库的最新API实现 - Based on the latest API implementation of 6tail lunar library
/// 参考文档：https://6tail.cn/calendar/api.html - Reference documentation: https://6tail.cn/calendar/api.html
class LunarService {
  /// 获取今日老黄历信息 - Get today's lunar calendar information
  /// 
  /// 为什么使用这个方法：
  /// 1. 提供完整的老黄历信息，包括农历日期、宜忌、节气等 - Provides complete lunar calendar information including lunar date, suitable/unsuitable activities, solar terms, etc.
  /// 2. 使用当前系统时间确保数据的实时性 - Uses current system time to ensure real-time data
  /// 3. 统一数据格式便于前端展示 - Unified data format for easy frontend display
  /// 
  /// @return Map<String, dynamic> 包含完整老黄历信息的Map - Map containing complete lunar calendar information
  /// 
  /// 返回数据结构说明 - Return data structure description:
  /// - lunar_date: 农历日期字符串 - Lunar date string
  /// - constellation: 星座 - Constellation
  /// - zodiac: 生肖 - Zodiac
  /// - ganzhi: 干支纪年 - Ganzhi year
  /// - solar_term: 节气 - Solar term
  /// - festivals: 公历节日列表 - Solar festivals list
  /// - lunar_festivals: 农历节日列表 - Lunar festivals list
  /// - yi: 宜做的事情列表 - List of suitable activities
  /// - ji: 忌做的事情列表 - List of unsuitable activities
  /// - five_elements: 五行 - Five elements
  /// - nayin: 纳音 - Nayin
  static Map<String, dynamic> getTodayLunarInfo() {
    try {
      // 获取当前日期 - Get current date
      // 为什么使用DateTime.now()：获取系统当前时间，确保老黄历信息的准确性
      // Why use DateTime.now(): Get current system time to ensure accuracy of lunar calendar information
      final now = DateTime.now();
      
      // 创建Solar对象（公历日期）- Create Solar object (Gregorian date)
      // 为什么使用Solar.fromYmd：lunar库的标准入口，从公历日期开始转换
      // Why use Solar.fromYmd: Standard entry point of lunar library, start conversion from Gregorian date
      final solar = Solar.fromYmd(now.year, now.month, now.day);
      
      // 转换为农历 - Convert to lunar calendar
      // 为什么调用getLunar()：将公历日期转换为农历日期，这是获取老黄历信息的基础
      // Why call getLunar(): Convert Gregorian date to lunar date, which is the foundation for getting lunar calendar information
      final lunar = solar.getLunar();
      
      // 获取八字信息 - Get BaZi information
      // 为什么获取八字：八字是中国传统命理学的重要组成部分，包含年月日时的天干地支
      // Why get BaZi: BaZi is an important part of traditional Chinese numerology, containing heavenly stems and earthly branches of year, month, day and hour
      final baZi = lunar.getEightChar();
      
      // 获取日期的宜忌信息 - Get suitable and unsuitable activities
      // 使用 lunar.getDayYi()/getDayJi() 获取宜忌列表
      // Why use getDayYi/getDayJi: Direct API for daily Yi/Ji lists in lunar library
      final yi = lunar.getDayYi();
      final ji = lunar.getDayJi();
      
      // 获取节气信息 - Get solar term information
      // 为什么获取节气：二十四节气是中国传统历法的重要组成部分，反映季节变化
      // Why get solar terms: The 24 solar terms are an important part of traditional Chinese calendar, reflecting seasonal changes
      final jieQi = lunar.getJieQi();
      
      // 获取节日信息 - Get festival information
      // 为什么获取节日：提供公历和农历节日信息，丰富用户体验
      // Why get festivals: Provide solar and lunar festival information to enrich user experience
      final festivals = solar.getFestivals();
      final lunarFestivals = lunar.getFestivals();
      
      return {
        // 农历日期 - Lunar date
        'lunar_date': '${lunar.getMonthInChinese()}月${lunar.getDayInChinese()}',
        
        // 星座 - Constellation
        'constellation': _getConstellation(now.month, now.day),
        
        // 生肖 - Zodiac
        'zodiac': lunar.getYearShengXiao(),
        
        // 干支纪年月日 - Ganzhi year, month, day
        'ganzhi': '${baZi.getYear()} ${baZi.getMonth()} ${baZi.getDay()}',
        
        // 节气 - Solar term
        'solar_term': jieQi,
        
        // 公历节日 - Solar festivals
        'festivals': festivals,
        
        // 农历节日 - Lunar festivals
        'lunar_festivals': lunarFestivals,
        
        // 宜 - Suitable activities
        'yi': yi,
        
        // 忌 - Unsuitable activities
        'ji': ji,
        
        // 五行 - Five elements
        'five_elements': baZi.getDayGan(),
        
        // 纳音 - Nayin
        'nayin': baZi.getDayNaYin(),
        
        // 额外信息 - Additional information
        'extra_info': {
          'lunar_year': lunar.getYearInChinese(),
          'lunar_month': lunar.getMonthInChinese(),
          'lunar_day': lunar.getDayInChinese(),
          'week_day': _getWeekDayInChinese(now.weekday),
          // 闰月判断：通过中文月份是否包含“闰”
          'is_leap_month': lunar.getMonthInChinese().contains('闰'),
        }
      };
    } catch (e) {
      // 如果lunar库调用失败，返回默认数据 - Return default data if lunar library fails
      // 为什么需要异常处理：确保服务的稳定性，即使lunar库出现问题也能提供基本信息
      // Why need exception handling: Ensure service stability, provide basic information even if lunar library has issues
      return _getDefaultLunarInfo();
    }
  }

  /// 获取指定日期的老黄历信息 - Get lunar calendar information for specific date
  /// 
  /// 为什么需要这个方法：
  /// 1. 支持用户查询历史或未来日期的老黄历信息 - Support users to query lunar calendar information for historical or future dates
  /// 2. 为日历组件提供数据支持 - Provide data support for calendar components
  /// 3. 满足用户个性化查询需求 - Meet users' personalized query needs
  /// 
  /// @param year 年份 - Year
  /// @param month 月份 - Month  
  /// @param day 日期 - Day
  /// @return Map<String, dynamic> 包含老黄历信息的Map - Map containing lunar calendar information
  static Map<String, dynamic> getLunarInfoForDate(int year, int month, int day) {
    try {
      // 创建Solar对象 - Create Solar object
      // 为什么使用传入的参数：允许用户查询任意指定日期的老黄历信息
      // Why use passed parameters: Allow users to query lunar calendar information for any specified date
      final solar = Solar.fromYmd(year, month, day);
      
      // 转换为农历 - Convert to lunar calendar
      final lunar = solar.getLunar();
      
      // 获取八字信息 - Get BaZi information
      final baZi = lunar.getEightChar();
      
      // 获取日期的宜忌信息 - Get suitable and unsuitable activities
      final yi = lunar.getDayYi();
      final ji = lunar.getDayJi();
      
      // 获取节气信息 - Get solar term information
      final jieQi = lunar.getJieQi();
      
      // 获取节日信息 - Get festival information
      final festivals = solar.getFestivals();
      final lunarFestivals = lunar.getFestivals();
      
      return {
        'lunar_date': '${lunar.getMonthInChinese()}月${lunar.getDayInChinese()}',
        'constellation': _getConstellation(month, day),
        'zodiac': lunar.getYearShengXiao(),
        'ganzhi': '${baZi.getYear()} ${baZi.getMonth()} ${baZi.getDay()}',
        'solar_term': jieQi,
        'festivals': festivals,
        'lunar_festivals': lunarFestivals,
        'yi': yi,
        'ji': ji,
        'five_elements': baZi.getDayGan(),
        'nayin': baZi.getDayNaYin(),
        'extra_info': {
          'lunar_year': lunar.getYearInChinese(),
          'lunar_month': lunar.getMonthInChinese(),
          'lunar_day': lunar.getDayInChinese(),
          'week_day': _getWeekDayInChinese(DateTime(year, month, day).weekday),
          'is_leap_month': lunar.getMonthInChinese().contains('闰'),
        }
      };
    } catch (e) {
      // 异常处理：返回默认数据确保服务稳定性
      // Exception handling: Return default data to ensure service stability
      return _getDefaultLunarInfo();
    }
  }

  /// 获取星座信息 - Get constellation information
  /// 
  /// 为什么需要这个方法：
  /// 1. lunar库可能不包含星座计算功能，需要自行实现 - Lunar library may not include constellation calculation, need to implement ourselves
  /// 2. 星座是现代用户关注的信息，增加用户体验 - Constellation is information that modern users care about, enhances user experience
  /// 3. 使用标准的星座日期划分算法 - Uses standard constellation date division algorithm
  /// 
  /// @param month 月份 - Month
  /// @param day 日期 - Day
  /// @return String 星座名称 - Constellation name
  static String _getConstellation(int month, int day) {
    // 十二星座的日期划分 - Date division of twelve constellations
    // 为什么使用这个数据结构：标准的星座日期划分，每个月包含两个星座的分界点
    // Why use this data structure: Standard constellation date division, each month contains boundary points of two constellations
    const constellations = [
      ['摩羯座', '水瓶座'], // 1月 - January
      ['水瓶座', '双鱼座'], // 2月 - February
      ['双鱼座', '白羊座'], // 3月 - March
      ['白羊座', '金牛座'], // 4月 - April
      ['金牛座', '双子座'], // 5月 - May
      ['双子座', '巨蟹座'], // 6月 - June
      ['巨蟹座', '狮子座'], // 7月 - July
      ['狮子座', '处女座'], // 8月 - August
      ['处女座', '天秤座'], // 9月 - September
      ['天秤座', '天蝎座'], // 10月 - October
      ['天蝎座', '射手座'], // 11月 - November
      ['射手座', '摩羯座'], // 12月 - December
    ];

    // 每个月星座变换的日期 - Date of constellation change each month
    // 为什么使用这些日期：这是天文学上确定的星座分界日期
    // Why use these dates: These are astronomically determined constellation boundary dates
    const dates = [20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22];
    
    // 参数验证 - Parameter validation
    // 为什么需要验证：防止数组越界和无效输入
    // Why need validation: Prevent array out of bounds and invalid input
    if (month < 1 || month > 12) return '未知';
    
    // 根据日期判断星座 - Determine constellation based on date
    // 为什么使用这个逻辑：如果日期小于分界日期，属于前一个星座，否则属于后一个星座
    // Why use this logic: If date is less than boundary date, belongs to previous constellation, otherwise belongs to next constellation
    return day < dates[month - 1] 
        ? constellations[month - 1][0] 
        : constellations[month - 1][1];
  }

  /// 获取星期几的中文表示 - Get Chinese representation of weekday
  /// 
  /// 为什么需要这个方法：
  /// 1. 提供中文的星期表示，符合中国用户习惯 - Provide Chinese weekday representation, conforming to Chinese user habits
  /// 2. DateTime.weekday返回的是数字，需要转换为中文 - DateTime.weekday returns numbers, need to convert to Chinese
  /// 3. 统一数据格式，保持界面一致性 - Unified data format, maintain interface consistency
  /// 
  /// @param weekday 星期几 (1-7, 1为周一) - Weekday (1-7, 1 is Monday)
  /// @return String 中文星期表示 - Chinese weekday representation
  static String _getWeekDayInChinese(int weekday) {
    // 中文星期表示数组 - Chinese weekday representation array
    // 为什么使用这个顺序：符合ISO 8601标准，周一为第一天
    // Why use this order: Conforms to ISO 8601 standard, Monday is the first day
    const weekDays = ['一', '二', '三', '四', '五', '六', '日'];
    
    // 参数验证 - Parameter validation
    if (weekday < 1 || weekday > 7) return '未知';
    
    // 返回中文星期表示 - Return Chinese weekday representation
    return '星期${weekDays[weekday - 1]}';
  }

  /// 获取默认老黄历信息 - Get default lunar calendar information
  /// 
  /// 为什么需要这个方法：
  /// 1. 当lunar库调用失败时提供备用数据 - Provide backup data when lunar library call fails
  /// 2. 确保服务的可用性和稳定性 - Ensure service availability and stability
  /// 3. 避免应用崩溃，提供基本的用户体验 - Avoid application crashes, provide basic user experience
  /// 
  /// 当lunar库调用失败时使用 - Used when lunar library call fails
  /// @return Map<String, dynamic> 默认老黄历数据 - Default lunar calendar data
  static Map<String, dynamic> _getDefaultLunarInfo() {
    final now = DateTime.now();
    
    // 为什么返回这些默认值：提供基本的老黄历信息，确保界面不会显示空白
    // Why return these default values: Provide basic lunar calendar information, ensure interface doesn't show blank
    return {
      'lunar_date': '腊月初八',
      'constellation': _getConstellation(now.month, now.day),
      'zodiac': '龙',
      'ganzhi': '甲辰年 丙子月 戊子日',
      'solar_term': '',
      'festivals': [],
      'lunar_festivals': [],
      'yi': ['祈福', '出行', '会友', '学习', '工作'],
      'ji': ['动土', '开仓', '搬家', '结婚'],
      'five_elements': '木',
      'nayin': '海中金',
      'extra_info': {
        'lunar_year': '甲辰年',
        'lunar_month': '腊月',
        'lunar_day': '初八',
        'week_day': _getWeekDayInChinese(now.weekday),
        'is_leap_month': false,
      }
    };
  }

  /// 获取农历月份信息 - Get lunar month information
  /// 
  /// 为什么需要这个方法：
  /// 1. 为日历组件提供月份数据 - Provide month data for calendar components
  /// 2. 支持用户浏览不同月份的农历信息 - Support users to browse lunar information of different months
  /// 3. 计算月份中的特殊日期和节日 - Calculate special dates and festivals in the month
  /// 
  /// @param year 年份 - Year
  /// @param month 月份 - Month
  /// @return Map<String, dynamic> 月份信息 - Month information
  static Map<String, dynamic> getLunarMonthInfo(int year, int month) {
    try {
      // 获取该月第一天 - Get first day of the month
      final firstDay = Solar.fromYmd(year, month, 1);
      final lunar = firstDay.getLunar();
      
      // 获取该月天数 - Get number of days in the month
      final daysInMonth = DateTime(year, month + 1, 0).day;
      
      // 收集该月所有日期的农历信息 - Collect lunar information for all dates in the month
      final List<Map<String, dynamic>> days = [];
      
      for (int day = 1; day <= daysInMonth; day++) {
        final dayInfo = getLunarInfoForDate(year, month, day);
        days.add({
          'day': day,
          'lunar_info': dayInfo,
        });
      }
      
      return {
        'year': year,
        'month': month,
        'lunar_year': lunar.getYearInChinese(),
        'lunar_month': lunar.getMonthInChinese(),
        'days': days,
      };
    } catch (e) {
      // 异常处理：返回基本月份信息
      // Exception handling: Return basic month information
      return {
        'year': year,
        'month': month,
        'lunar_year': '二零二四年',
        'lunar_month': '正月',
        'days': [],
      };
    }
  }
}